/*
 * Copyright (C) YiHua Computer Co., Ltd. 1999-2012. All rights reserved.
 * 项目:ATMC II
 * 作者:YiHua Computer
 * 创建时间:
 * 更新时间:
 */
package cn.mjnxin.iot.base.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.SocketException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;

import cn.mjnxin.iot.base.constant.ConstantValue;

/**
 * 各种转换工具，包括但不限于：
 * 字节、整数、长整数等数据类型之间的拆分和转换。<br/>
 * 还包括BCD码，十六进制码，网络字节序等等相互转换
 * Big Endian   ：将高序字节存储在起始地址
 * Little Endian：将低序字节存储在起始地址
 * @author CLG 2023年10月10日
 * @version V1.0.0
 */
public class MixUtil {
    private final static String HEX = "0123456789ABCDEF";

    private final static String regex="^[A-Fa-f0-9]+$";
      
    public static boolean isHex(String str) {
        return str.matches(regex);
    }
    
    /**
     * 字节数组转换成长整型。(网络字节序，高字节在前)
     *
     * @param b byte[] 字节数组。
     * @param offset int
     * @return long 长整数形式。
     */
    public final static long byte2long(byte[] b, int offset) {
        return ((long) b[offset + 7] & 0xff) | (((long) b[offset + 6] & 0xff) << 8)
                | (((long) b[offset + 5] & 0xff) << 16) | (((long) b[offset + 4] & 0xff) << 24)
                | (((long) b[offset + 3] & 0xff) << 32) | (((long) b[offset + 2] & 0xff) << 40)
                | (((long) b[offset + 1] & 0xff) << 48) | ((long) b[offset] << 56);
    }

    /**
     * 低字节在前，高字节在后字节流转换为整型
     *
     * @param buf byte[] 字节数组。
     * @param offset int
     * @return long 长整数形式。
     */
    public final static long Sbyte2long(byte[] buf, int offset) {
        return ((long) buf[offset] & 0xff) | (((long) buf[offset + 1] & 0xff) << 8) | (((long) buf[offset + 2] & 0xff) << 16)
                | (((long) buf[offset + 3] & 0xff) << 24) | (((long) buf[offset + 4] & 0xff) << 32)
                | (((long) buf[offset + 5] & 0xff) << 40) | (((long) buf[offset + 6] & 0xff) << 48)
                | ((long) buf[offset + 7] << 56);
    }

    /**
     * 字节数组转换成长整型。(网络字节序，高字节在前)
     *
     * @param b 字节数组。
     * @return 长整数形式。
     */
    public final static long byte2long(byte[] b) {
        return ((long) b[7] & 0xff) | (((long) b[6] & 0xff) << 8) | (((long) b[5] & 0xff) << 16)
                | (((long) b[4] & 0xff) << 24) | (((long) b[3] & 0xff) << 32) | (((long) b[2] & 0xff) << 40)
                | (((long) b[1] & 0xff) << 48) | ((long) b[0] << 56);
    }

    /**
     * 低字节在前，高字节在后字节流转换为整型
     *
     * @param buf 字节数组。
     * @return 长整数形式。
     */
    public final static long Sbyte2long(byte[] buf) {
        return ((long) buf[0] & 0xff) | (((long) buf[1] & 0xff) << 8) | (((long) buf[2] & 0xff) << 16)
                | (((long) buf[3] & 0xff) << 24) | (((long) buf[4] & 0xff) << 32) | (((long) buf[5] & 0xff) << 40)
                | (((long) buf[6] & 0xff) << 48) | ((long) buf[7] << 56);
    }

    /**
     * 长整型转换成字节。(网络字节序，高字节在前)
     *
     * @param l 长整数。
     * @return 长度为8的字节数组。
     */
    public final static byte[] long2byte(long l) {
        byte[] b = new byte[8];
        b[0] = (byte) (l >>> 56 & 0xFF);
        b[1] = (byte) (l >>> 48 & 0xFF);
        b[2] = (byte) (l >>> 40 & 0xFF);
        b[3] = (byte) (l >>> 32 & 0xFF);
        b[4] = (byte) (l >>> 24 & 0xFF);
        b[5] = (byte) (l >>> 16 & 0xFF);
        b[6] = (byte) (l >>> 8 & 0xFF);
        b[7] = (byte) (l & 0xFF);
        return b;
    }

    /**
     * 长整型转换成字节。(网络字节序，高字节在前)
     *
     * @param l 长整数。
     * @return 长度为8的字节数组。
     */
    public final static byte[] slong2byte(long l) {
        byte[] b = new byte[8];
        b[7] = (byte) (l >>> 56 & 0xFF);
        b[6] = (byte) (l >>> 48 & 0xFF);
        b[5] = (byte) (l >>> 40 & 0xFF);
        b[4] = (byte) (l >>> 32 & 0xFF);
        b[3] = (byte) (l >>> 24 & 0xFF);
        b[2] = (byte) (l >>> 16 & 0xFF);
        b[1] = (byte) (l >>> 8 & 0xFF);
        b[0] = (byte) (l & 0xFF);
        return b;
    }

    /**
     * 长整型转换成字节。(网络字节序，高字节在前)
     *
     * @param l 长整数。
     * @param buf 存放转换结果的字节数组。
     * @param offset 存放位置的偏移地址。
     */
    public final static void long2byte(long l, byte[] buf, int offset) {
        buf[offset] = (byte) (l >>> 56 & 0xFF);
        buf[offset + 1] = (byte) (l >>> 48 & 0xFF);
        buf[offset + 2] = (byte) (l >>> 40 & 0xFF);
        buf[offset + 3] = (byte) (l >>> 32 & 0xFF);
        buf[offset + 4] = (byte) (l >>> 24 & 0xFF);
        buf[offset + 5] = (byte) (l >>> 16 & 0xFF);
        buf[offset + 6] = (byte) (l >>> 8 & 0xFF);
        buf[offset + 7] = (byte) (l & 0xFF);
    }

    /**
     * 长整型转换成字节。(网络字节序，高字节在前)
     *
     * @param l 长整数。
     * @param buf 存放转换结果的字节数组。
     * @param offset 存放位置的偏移地址。
     * @author zhangyong 2004-05-27
     */
    public final static void Slong2byte(long l, byte[] buf, int offset) {
        buf[offset + 7] = (byte) (l >>> 56 & 0xFF);
        buf[offset + 6] = (byte) (l >>> 48 & 0xFF);
        buf[offset + 5] = (byte) (l >>> 40 & 0xFF);
        buf[offset + 4] = (byte) (l >>> 32 & 0xFF);
        buf[offset + 3] = (byte) (l >>> 24 & 0xFF);
        buf[offset + 2] = (byte) (l >>> 16 & 0xFF);
        buf[offset + 1] = (byte) (l >>> 8 & 0xFF);
        buf[offset] = (byte) (l & 0xFF);
    }

    /**
     * 字节数组转换成整型。(网络字节序，高字节在前)
     *
     * @param buf 字节数组。
     * @param offset 待转换字节开始的位置。
     * @return 整数形式。
     */
    public final static int byte2int(byte[] buf, int offset) {
        return (buf[offset + 3] & 0xff) | ((buf[offset + 2] & 0xff) << 8) | ((buf[offset + 1] & 0xff) << 16)
                | ((buf[offset] & 0xff) << 24);
    }

    /**
     * 低字节在前，高字节在后字节流转换为整型
     *
     * @param buf byte[]
     * @param offset int
     * @return int
     */
    public final static int Sbyte2int(byte[] buf, int offset) { // 读取4个.
        return (buf[offset] & 0xff) | ((buf[offset + 1] << 8) & 0xff00) | (((buf[offset + 2] << 16) & 0xff0000))
                | (((buf[offset + 3] << 24) & 0xff000000));
    }

    /**
     * 字节数组转换成整型。(网络字节序，高字节在前)
     *
     * @param buf 字节数组。
     * @return 整数形式。
     */
    public final static int byte2int(byte[] buf) {
        return (buf[3] & 0xff) | ((buf[2] & 0xff) << 8) | ((buf[1] & 0xff) << 16) | ((buf[0] & 0xff) << 24);
    }

    /**
     * 低字节在前，高字节在后字节流转换为整型
     *
     * @param buf 字节数组。
     * @return 整数形式。
     */
    public final static int Sbyte2int(byte[] buf) {
        return (buf[0] & 0xff) | ((buf[1] & 0xff) << 8) | ((buf[2] & 0xff) << 16) | ((buf[3] & 0xff) << 24);
    }

    /**
     * 整型转换成字节。(网络字节序，高字节在前)
     *
     * @param i 整数。
     * @param buf 存放转换结果的字节数组。
     * @param offset 存放位置的偏移地址。
     */
    public final static void int2byte(int i, byte[] buf, int offset) {
        buf[offset    ] = (byte) (i >>> 24 & 0xFF);
        buf[offset + 1] = (byte) (i >>> 16 & 0xFF);
        buf[offset + 2] = (byte) (i >>> 8 & 0xFF);
        buf[offset + 3] = (byte) (i & 0xFF);
    }

    /**
     * 低字节在前，高字节在后整型转换为字符串
     *
     * @param i int
     * @param buf byte[]
     * @param offset int
     */
    public final static void Sint2byte(int i, byte[] buf, int offset) {
        buf[offset + 3] = (byte) (i >>> 24 & 0xFF);
        buf[offset + 2] = (byte) (i >>> 16 & 0xFF);
        buf[offset + 1] = (byte) (i >>> 8 & 0xFF);
        buf[offset    ] = (byte) (i & 0xFF);
    }

    /**
     * 整型转换成字节。(网络字节序，高字节在前)
     *
     * @param i 整数。
     * @return 长度为4的字节数组。
     */
    public final static byte[] int2byte(int i) {
        byte[] b = new byte[4];
        b[0] = (byte) (i >>> 24 & 0xFF);
        b[1] = (byte) (i >>> 16 & 0xFF);
        b[2] = (byte) (i >>> 8 & 0xFF);
        b[3] = (byte) (i & 0xFF);
        return b;
    }

    /**
     * 低字节在前，高字节在后整型转换为字符串
     *
     * @param i 整数。
     * @return 长度为4的字节数组。
     */
    public final static byte[] Sint2byte(int i) {
        byte[] b = new byte[4];
        b[3] = (byte) (i >>> 24 & 0xFF);
        b[2] = (byte) (i >>> 16 & 0xFF);
        b[1] = (byte) (i >>> 8 & 0xFF);
        b[0] = (byte) (i & 0xFF);
        return b;
    }

    /**
     * 字节数组转换成整型。(网络字节序，高字节在前)
     *
     * @param buf 字节数组。
     * @param offset 待转换字节开始的位置。
     * @return 短整数形式。
     */
    public final static short byte2short(byte[] buf, int offset) {
        return (short) ((buf[offset + 1] & 0xff) | ((buf[offset] & 0xff) << 8));
    }

    /**
     * 低字节在前，高字节在后字节流转换为整型
     *
     * @param buf byte[]
     * @param offset int
     * @return 短整数形式。
     */
    public final static short Sbyte2short(byte[] buf, int offset) { 
        return (short) ((buf[offset] & 0xff) | ((buf[offset + 1] << 8) & 0xff00));
    }

    /**
     * 字节数组转换成整型。(网络字节序，高字节在前)
     *
     * @param buf 字节数组。
     * @return 短整数形式。
     */
    public final static short byte2short(byte[] buf) {
        return (short) ((buf[1] & 0xff) | ((buf[0] & 0xff) << 8));
    }

    /**
     * 低字节在前，高字节在后字节流转换为整型
     *
     * @param buf 字节数组。
     * @return 短整数形式。
     */
    public final static short Sbyte2short(byte[] buf) {
        return (short)((buf[0] & 0xff) | ((buf[1] & 0xff) << 8));
    }

    /**
     * 短整型转换成字节。(网络字节序，高字节在前)
     *
     * @param s 短整数。
     * @param buf 存放转换结果的字节数组。
     * @param offset 存放位置的偏移地址。
     */
    public final static void short2byte(short s, byte[] buf, int offset) {
        buf[offset] = (byte) (s >>> 8 & 0xFF);
        buf[offset + 1] = (byte) (s & 0xFF);
    }

    /**
     * 短整型转换成字节。(网络字节序，高字节在前)
     *
     * @param s 短整数。
     * @param buf 存放转换结果的字节数组。
     * @param offset 存放位置的偏移地址。
     */
    public final static void short2byte(int s, byte[] buf, int offset){
        buf[offset] = (byte) (s >>> 8 & 0xFF);
        buf[offset + 1] = (byte) (s & 0xFF);
    }

    /**
     * 低字节在前，高字节在后整型转换为字符串
     *
     * @param s 短整数。
     * @param buf 存放转换结果的字节数组。
     * @param offset 存放位置的偏移地址。
     */
    public final static void Sshort2byte(short s, byte[] buf, int offset) {
        buf[offset + 1] = (byte) (s >>> 8 & 0xFF);
        buf[offset] = (byte) (s & 0xFF);
    }

    /**
     * 低字节在前，高字节在后整型转换为字符串
     *
     * @param s 短整数。
     * @param buf 存放转换结果的字节数组。
     * @param offset 存放位置的偏移地址。
     */
    public final static void Sshort2byte(int s, byte[] buf, int offset) {
        buf[offset + 1] = (byte) (s >>> 8);
        buf[offset] = (byte) (s & 0xFF);
    }

    /**
     * 短整型转换成字节。(网络字节序，高字节在前)
     *
     * @param s 短整数。
     * @return 长度为4的字节数组。
     */
    public final static byte[] short2byte(short s) {
        byte[] b = new byte[2];
        b[0] = (byte) (s >>> 8 & 0xFF);
        b[1] = (byte) (s & 0xFF);
        return b;
    }

    /**
     * 低字节在前，高字节在后整型转换为字符串
     *
     * @param s 短整数。
     * @return 长度为4的字节数组。
     */
    public final static byte[] Sshort2byte(short s) {
        byte[] b = new byte[2];
        b[1] = (byte) (s >>> 8 & 0xFF);
        b[0] = (byte) (s & 0xFF);
        return b;
    }

    /***
     * 根据实际长度返回,不补任何东西.
     *
     * @param l long
     * @return String 一个16进制的字符串.
     */
    public final static String long2hex(long l) {
        int tmp;
        // 不断的移动，4个分一小段，移位和与或操作。
        char[] bb = new char[16];
        for (int index = 0; index < 64; index += 4) {
            tmp = (int) ((l >>> index) & 0x00000000000F);
            tmp = getHex(tmp);
            bb[15 - index / 4] = (char) tmp;
        }
        return new String(bb);
    }

    /***
     * 根据实际长度返回,不补任何东西.
     *
     * @param l long
     * @return String 一个16进制的字符串.
     */
    public final static String long2hexA(long l) {
        char[] cc = new char[16];
        int len = 0;
        int tmp = 0;
        for (int offset = 60; offset >= 0; offset -= 4) {
            tmp = ((int) (l >>> offset)) & 0x0f;
            if ((tmp == 0) && (len == 0)) { // 开头是0则省略调.
                continue;
            }
            else {
                tmp = getHex(tmp);
            }
            // 遇到正常字符.
            cc[len++] = (char) tmp;
        }
        return new String(cc, 0, len);
    }

    /**
     * 整型转换成16进制,,负数最后要在最高位加1就是8
     *
     * @param i int
     * @return 16进制度字符串。
     */
    public final static String int2hex(int i) {
        int tmp;
        // 不断的移动，4个分一小段，移位和与或操作。
        char[] bb = new char[8];
        for (int index = 0; index < 32; index += 4) {
            tmp = (int) ((i >>> index) & 0x0000000F);
            tmp = getHex(tmp);
            bb[7 - index / 4] = (char) tmp;
        }
        return new String(bb);
    }

    /***
     * 根据实际长度返回,不补任何东西.
     *
     * @param i int
     * @return String 一个16进制的字符串.
     */
    public final static String int2hexA(int i) {
        char[] c = new char[8];
        int len = 0;
        int tmp = 0;
        for (int offset = 28; offset >= 0; offset -= 4) {
            tmp = (i >>> offset) & 0x0f;
            if ((tmp == 0) && (len == 0)) { // 开头是0则省略调.
                continue;
            }
            else {
                tmp = getHex(tmp);
            }
            // 遇到正常字符.
            c[len++] = (char) tmp;
        }
        return new String(c, 0, len);
    }

    /**
     * 整型转换成16进制,,负数最后要在最高位加1就是8
     *
     * @param s int
     * @return 16进制度字符串。
     */
    public final static String short2hex(int s) {
        int tmp;
        // 不断的移动，4个分一小段，移位和与或操作。
        char[] bb = new char[4];
        for (int index = 0; index < 16; index += 4) {
            tmp = (int) ((s >>> index) & 0x0000000F);
            tmp = getHex(tmp);
            bb[3 - index / 4] = (char) tmp;
        }
        return new String(bb);
    }

    /***
     * 根据实际长度返回,不补任何东西.
     *
     * @param s int
     * @return String 一个16进制的字符串.
     */
    public final static String short2hexA(int s) {
        char[] c = new char[8];
        int len = 0;
        int tmp = 0;
        for (int offset = 12; offset >= 0; offset -= 4) {
            tmp = (s >>> offset) & 0x0f;
            if ((tmp == 0) && (len == 0)) { // 开头是0则省略调.
                continue;
            }
            else {
                tmp = getHex(tmp);
            }
            // 遇到正常字符.
            c[len++] = (char) tmp;
        }
        return new String(c, 0, len);
    }

    public static String byte2hex(byte b) {
        String hex = "";
        int inch = ((b >>> 4) & 0x0F);
        inch = getHex(inch);
        hex += (char) inch;

        inch = (b & 0x0F);
        inch = getHex(inch);
        hex += (char) inch;
        return hex;
    }

    public final static String hex2str(String hex, int start, int end) {
        return new String(MixUtil.hex2bytes(hex.substring(start, end)));
    }

    public final static String str2hex(String str) {
        return MixUtil.bytes2hex(str.getBytes());
    }

    public final static long hex2long(String h) {
        String hexStr = h.toUpperCase();
        long ret = 0;
        for (int i = 0, len = hexStr.length(); i < len; i++) {
            ret = (ret << 4) + HEX.indexOf(hexStr.charAt(i));
        }

        return ret;
    }

    public final static long hex2Slong(String h) {
    	return Sbyte2long(hex2bytes(h));
    }

    public final static int hex2int(String h) {
        int ret = 0;
        for (int i = 0, len = h.length(); i < len; i++) {
            ret = (ret << 4) + HEX.indexOf(h.charAt(i));
        }

        return ret;
    }

    public final static int hex2Sint(String h)
    {
    	return Sbyte2int(hex2bytes(h));
    }

    public final static short hex2short(String h) {
        short ret = 0;
        for (int i = 0, len = h.length(); i < len; i++) {
            ret = (short) ((ret << 4) + HEX.indexOf(h.charAt(i)));
        }

        return ret;
    }

    public final static short hex2Sshort(String h) {
    	return Sbyte2short(hex2bytes(h));
    }

    // 默认要求是大写十六进制，否则出错
    public final static byte hex2byte(String h) {
        byte ret = 0;
        for (int i = 0, len = h.length(); i < len; i++) {
            ret = (byte) ((ret << 4) + HEX.indexOf(h.charAt(i)));
        }

        return ret;
    }


    // 默认要求是大写十六进制，否则出错
    public final static byte hex2byte(char c) {
        byte b = (byte) HEX.indexOf(c);
        return b;
    }

    /**
     * 将字节内容按照二进制码打印出来
     *
     * @param buf byte
     * @return String
     */
    public final static String toBinary(byte buf) {
        StringBuilder chars = new StringBuilder();
        int inch = 0;
        int j;
        for (j = 7; j >= 0; j--) {
            inch = ((buf >>> j) & 0x01);
            if (inch == 0) {
                chars.append('0');
            }
            else {
                chars.append('1');
            }
        }
        return chars.toString();
    }

    /**
     * 将字节数组内容按照二进制码打印出来
     *
     * @param buf byte[]
     * @return String
     */
    public final static String toBinary(byte[] buf) {
        int len = buf.length;
        StringBuilder chars = new StringBuilder();
        byte tmp;
        int inch = 0;
        int j;
        for (int i = 0; i < len; i++) {
            tmp = buf[i];
            for (j = 7; j >= 0; j--) {
                inch = ((tmp >>> j) & 0x01);
                if (inch == 0) {
                    chars.append('0');
                }
                else {
                    chars.append('1');
                }
            }
        }
        return chars.toString();
    }

    /**
     * 将二进制码转换为字节数组
     *
     * @param buf byte[]
     * @return String
     */
    public final static byte[] fromBinary(String b) {
        int length = b.length();
        if ((length % 8) != 0) {
            b = "0000000" + b;
        }

        b = b.substring(b.length() % 8, b.length());

        byte[] tmp = new byte[length / 8];
        for (int i = 0, index = 0; i < length; i = i + 8, index++) {
            tmp[index] = (byte) Integer.parseInt(b.substring(i, i + 8), 2);
        }

        return tmp;
    }

    /**
     * 将由0,1组成的长度为4的字符串转化为对应的16进制字符串表示，例如输入字符串"1111",输出值为"F" <br/>
     * 注意此方法输入的字符串长度最大为4，一次只能转换成为一个16进制字符
     *
     * @param b 0,1组成的字符串
     * @return 转换后的16进制字符
     */
    public static char binary2Hex(String b) {
        int len = b.length();
        if (len > 4) {
            return '\0';
        }

        if ((len % 4) != 0) {
            b = "000" + b;
            b = b.substring(b.length() % 4, b.length());
        }

        int result = Integer.parseInt(b, 2);
        switch (result) {
            case 0:
                return '0';
            case 1:
                return '1';
            case 2:
                return '2';
            case 3:
                return '3';
            case 4:
                return '4';
            case 5:
                return '5';
            case 6:
                return '6';
            case 7:
                return '7';
            case 8:
                return '8';
            case 9:
                return '9';
            case 10:
                return 'A';
            case 11:
                return 'B';
            case 12:
                return 'C';
            case 13:
                return 'D';
            case 14:
                return 'E';
            case 15:
                return 'F';
            default:
                return '\0';
        }
    }

    /**
     * 将0,1组成的字符串转换为对应的十六进制字符串，例如输入字符串"111100001111"输出为"FOF" 此方法输入的字符串长度不限
     *
     * @param b 0,1组成的字符串
     * @return 十六进制字符串
     */
    public static String binary2hex(String b) {
        int length = b.length();
        if ((length % 4) != 0) {
            b = "000" + b;
            b = b.substring(b.length() % 4, b.length());
        }

        StringBuilder str = new StringBuilder();

        for (int i = 0, len = b.length(); i < len / 4; i++) {
            str.append(binary2Hex(b.substring(i * 4, i * 4 + 4)));
        }
        return str.toString();
    }

    /**
     * BCD码转为10进制串(阿拉伯数据)<br/>
     * * BCD与十进制字符串的转换.<br/>
     * BCD（Binary Coded Decimal）是用二进制编码表示的十进制数，<br/>
     * 十进制数采用0~9十个数字，是人们最常用的。在计算机中，同一个数可以用两种BCD格式来表示：<br/>
     * ①压缩的BCD码 ②非压缩的BCD码<br/>
     * 压缩的BCD码：<br/>
     * 压缩的BCD码用4位二进制数表示一个十进制数位，整个十进制数用一串BCD码来表示。<br/>
     * 例如，十进制数59表示成压缩的BCD码为0101 1001，十进制数1946表示成压缩的BCD码为0001 1001 0100 0110。<br/>
     * 非压缩的BCD码：<br/>
     * 非压缩的BCD码用8位二进制数表示一个十进制数位，其中低4位是BCD码，高4位是0。<br/>
     * 例如，十进制数78表示成压缩的BCD码为0111 1000。<br/>
     * 从键盘输入数据时，计算机接收的是ASCII码，要将ASCII码表示的数转换成BCD码是很简单的，<br/>
     * 只要把ASCII码的高4位清零即可。反之，如果要把BCD码转换成ASII码，只要把BCD码每位扩充0000即可。
     *
     * @param buf BCD码
     * @return String 10进制串
     */
    public static String bcd2str(byte[] buf)
    {
        if (buf.length == 0) {
            return "";
        }

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < buf.length; i++) {
            sb.append((char) getHex(((buf[i] & 0xff) >>> 4)));
            sb.append((char) getHex(((buf[i] & 0x0f))));
        }
        return sb.toString();
    }
    //14081501
    public static String bcdHex2DigitStr(String bcdHex) {
        if (bcdHex.length() == 0) {
            return "";
        }

        StringBuilder sb = new StringBuilder();
        for (int i = 0, len = bcdHex.length() / 2; i < len; i++) {
        	int tmp = HEX.indexOf(bcdHex.charAt(i+i))*16 + HEX.indexOf(bcdHex.charAt(i+i+1));
        	if (tmp <10) {
                sb.append("0"+tmp);
        	}
        	else {
                sb.append(""+tmp);
        	}
        }
        return sb.toString();
    }

    /**
     * 10进制串转为BCD码<br/>
     *
     * @param str 10进制串
     * @return byte[] BCD码
     */
    public static byte[] str2bcd(String str) {
        if (str.length() == 0) {
            return new byte[0];
        }

        String newStr = str;
        // 奇数个数字需左补零
        if (newStr.length() % 2 != 0) {
            newStr = "0" + newStr;
        }
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        char[] cs = newStr.toCharArray();
        for (int i = 0; i < cs.length; i += 2) {
            int high = 0;
            if (cs[i] >= '0' && cs[i] <= '9') {
                high = cs[i] - 48;
            }
            if (cs[i] >= 'A' && cs[i] <= 'Z') {
                high = cs[i] - 55;
            }

            int low = 0;
            if (cs[i + 1] >= '0' && cs[i + 1] <= '9') {
                low = cs[i + 1] - 48;
            }
            if (cs[i + 1] >= 'A' && cs[i + 1] <= 'Z') {
                low = cs[i + 1] - 55;
            }
            baos.write(high << 4 | low);
        }
        return baos.toByteArray();
    }

    /**
     * 将字节数组内容按照十六进制码打印出来
     *
     * @param buf byte[]
     * @param split String 分隔符
     * @return String
     */
    public final static String bytes2hex(byte[] buf, String split) {
        if ((split == null) || (split.length() == 0)) {
            return bytes2hex(buf);
        }

        if ((buf == null) || (buf.length == 0)) {
            return "";
        }
        StringBuilder chars = new StringBuilder();
        for (byte tmp : buf) {
            chars.append(split);
            int inch = ((tmp >>> 4) & 0x0F);
            inch = getHex(inch);
            chars.append((char) inch);

            inch = (tmp & 0x0F);
            inch = getHex(inch);
            chars.append((char) inch);
        }

        return chars.substring(split.length());
    }

    /**
     * 将字节数组内容按照十六进制码打印出来
     *
     * @param buf byte[]
     * @param split String 分隔符
     * @return String
     */
    public final static String bytes2hex(byte[] buf) {
        if ((buf == null) || (buf.length == 0)) {
            return "";
        }

        StringBuilder chars = new StringBuilder();
        for (byte b : buf) {
            int inch = ((b >>> 4) & 0x0F);
            inch = getHex(inch);
            chars.append((char) inch);

            inch = (b & 0x0F);
            inch = getHex(inch);
            chars.append((char) inch);
        }

        return chars.toString();
    }

    /**
     * 将十六进制码字符串转换成字节数组内容
     *
     * @param str 十六进制码字符串
     * @return String
     */
    public final static byte[] hex2bytes(String str) {
        str = str.toUpperCase();
        int len = str.length() / 2;
        byte[] buf = new byte[len];
        int inch = 0;
        for (int i = 0; i < len; i++) {
            inch = str.charAt(i + i);
            if (inch >= 65) {
                buf[i] = (byte) (((inch - 55) << 4) & 0xF0);
            }
            else {
                buf[i] = (byte) (((inch - 48) << 4) & 0xF0);
            }
            inch = str.charAt(i + i + 1);
            if (inch >= 65) {
                buf[i] = (byte) (buf[i] | ((inch - 55) & 0x0F));
            }
            else {
                buf[i] = (byte) (buf[i] | ((inch - 48) & 0x0F));
            }
        }
        return buf;
    }

    private static int getHex(int i) {
        if (i >= 10) {
            return i + 55;
        }
        else {
            return i + 48;
        }
    }

    public static String replaceHex(String hex, String matchStr, String escapeStr) {
        String retStr = hex;
        int matchLen = matchStr.length();
        for (int start = retStr.length() - matchLen; start >= 0; start--) {
            if (start % 2 == 1) {
                continue;
            }
            if (retStr.substring(start, retStr.length()).startsWith(matchStr)) {
                retStr = retStr.substring(0, start) + escapeStr + retStr.substring(start + matchLen, retStr.length());
            }
        }
        return retStr;
    }
    
//    /**
//     * 计算CRC16校验码
//     *
//     * @param bytes
//     * @return
//     */
//    public static String getCRC16(byte[] bytes) {
////      ModBus 通信协议的 CRC ( 冗余循环校验码含2个字节, 即 16 位二进制数。
////      CRC 码由发送设备计算, 放置于所发送信息帧的尾部。
////      接收信息设备再重新计算所接收信息 (除 CRC 之外的部分）的 CRC,
////      比较计算得到的 CRC 是否与接收到CRC相符, 如果两者不相符, 则认为数据出错。
////
////      1) 预置 1 个 16 位的寄存器为十六进制FFFF(即全为 1) , 称此寄存器为 CRC寄存器。
////      2) 把第一个 8 位二进制数据 (通信信息帧的第一个字节) 与 16 位的 CRC寄存器的低 8 位相异或, 把结果放于 CRC寄存器。
////      3) 把 CRC 寄存器的内容右移一位( 朝低位)用 0 填补最高位, 并检查右移后的移出位。
////      4) 如果移出位为 0, 重复第 3 步 ( 再次右移一位); 如果移出位为 1, CRC 寄存器与多项式A001 ( 1010 0000 0000 0001) 进行异或。
////      5) 重复步骤 3 和步骤 4, 直到右移 8 次,这样整个8位数据全部进行了处理。
////      6) 重复步骤 2 到步骤 5, 进行通信信息帧下一个字节的处理。
////      7) 将该通信信息帧所有字节按上述步骤计算完成后,得到的16位CRC寄存器的高、低字节进行交换。
////      8) 最后得到的 CRC寄存器内容即为 CRC码。
//
//        int CRC = 0x0000ffff;
//        int POLYNOMIAL = 0x0000a001;
//
//        int i, j;
//        for (i = 0; i < bytes.length; i++) {
//            //CRC ^= (int) bytes[i];
//        	CRC ^= ((int) bytes[i] & 0x000000ff);
//            for (j = 0; j < 8; j++) {
//                if ((CRC & 0x00000001) == 1) {
//                    CRC >>= 1;
//                    CRC ^= POLYNOMIAL;
//                } else {
//                    CRC >>= 1;
//                }
//            }
//        }
//        // 高低位转换，看情况使用（譬如本人这次对led彩屏的通讯开发就规定校验码高位在前低位在后，也就不需要转换高低位)
//        // CRC = ( (CRC & 0x0000FF00) >> 8) | ( (CRC & 0x000000FF ) << 8);
////        return Integer.toHexString(CRC);
//        return String.format("%04X", CRC);
//    }
    
    private static byte[] crc16_h = {
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40
    };

    private static byte[] crc16_l = {
            (byte) 0x00, (byte) 0xC0, (byte) 0xC1, (byte) 0x01, (byte) 0xC3, (byte) 0x03, (byte) 0x02, (byte) 0xC2, (byte) 0xC6, (byte) 0x06, (byte) 0x07, (byte) 0xC7, (byte) 0x05, (byte) 0xC5, (byte) 0xC4, (byte) 0x04,
            (byte) 0xCC, (byte) 0x0C, (byte) 0x0D, (byte) 0xCD, (byte) 0x0F, (byte) 0xCF, (byte) 0xCE, (byte) 0x0E, (byte) 0x0A, (byte) 0xCA, (byte) 0xCB, (byte) 0x0B, (byte) 0xC9, (byte) 0x09, (byte) 0x08, (byte) 0xC8,
            (byte) 0xD8, (byte) 0x18, (byte) 0x19, (byte) 0xD9, (byte) 0x1B, (byte) 0xDB, (byte) 0xDA, (byte) 0x1A, (byte) 0x1E, (byte) 0xDE, (byte) 0xDF, (byte) 0x1F, (byte) 0xDD, (byte) 0x1D, (byte) 0x1C, (byte) 0xDC,
            (byte) 0x14, (byte) 0xD4, (byte) 0xD5, (byte) 0x15, (byte) 0xD7, (byte) 0x17, (byte) 0x16, (byte) 0xD6, (byte) 0xD2, (byte) 0x12, (byte) 0x13, (byte) 0xD3, (byte) 0x11, (byte) 0xD1, (byte) 0xD0, (byte) 0x10,
            (byte) 0xF0, (byte) 0x30, (byte) 0x31, (byte) 0xF1, (byte) 0x33, (byte) 0xF3, (byte) 0xF2, (byte) 0x32, (byte) 0x36, (byte) 0xF6, (byte) 0xF7, (byte) 0x37, (byte) 0xF5, (byte) 0x35, (byte) 0x34, (byte) 0xF4,
            (byte) 0x3C, (byte) 0xFC, (byte) 0xFD, (byte) 0x3D, (byte) 0xFF, (byte) 0x3F, (byte) 0x3E, (byte) 0xFE, (byte) 0xFA, (byte) 0x3A, (byte) 0x3B, (byte) 0xFB, (byte) 0x39, (byte) 0xF9, (byte) 0xF8, (byte) 0x38,
            (byte) 0x28, (byte) 0xE8, (byte) 0xE9, (byte) 0x29, (byte) 0xEB, (byte) 0x2B, (byte) 0x2A, (byte) 0xEA, (byte) 0xEE, (byte) 0x2E, (byte) 0x2F, (byte) 0xEF, (byte) 0x2D, (byte) 0xED, (byte) 0xEC, (byte) 0x2C,
            (byte) 0xE4, (byte) 0x24, (byte) 0x25, (byte) 0xE5, (byte) 0x27, (byte) 0xE7, (byte) 0xE6, (byte) 0x26, (byte) 0x22, (byte) 0xE2, (byte) 0xE3, (byte) 0x23, (byte) 0xE1, (byte) 0x21, (byte) 0x20, (byte) 0xE0,
            (byte) 0xA0, (byte) 0x60, (byte) 0x61, (byte) 0xA1, (byte) 0x63, (byte) 0xA3, (byte) 0xA2, (byte) 0x62, (byte) 0x66, (byte) 0xA6, (byte) 0xA7, (byte) 0x67, (byte) 0xA5, (byte) 0x65, (byte) 0x64, (byte) 0xA4,
            (byte) 0x6C, (byte) 0xAC, (byte) 0xAD, (byte) 0x6D, (byte) 0xAF, (byte) 0x6F, (byte) 0x6E, (byte) 0xAE, (byte) 0xAA, (byte) 0x6A, (byte) 0x6B, (byte) 0xAB, (byte) 0x69, (byte) 0xA9, (byte) 0xA8, (byte) 0x68,
            (byte) 0x78, (byte) 0xB8, (byte) 0xB9, (byte) 0x79, (byte) 0xBB, (byte) 0x7B, (byte) 0x7A, (byte) 0xBA, (byte) 0xBE, (byte) 0x7E, (byte) 0x7F, (byte) 0xBF, (byte) 0x7D, (byte) 0xBD, (byte) 0xBC, (byte) 0x7C,
            (byte) 0xB4, (byte) 0x74, (byte) 0x75, (byte) 0xB5, (byte) 0x77, (byte) 0xB7, (byte) 0xB6, (byte) 0x76, (byte) 0x72, (byte) 0xB2, (byte) 0xB3, (byte) 0x73, (byte) 0xB1, (byte) 0x71, (byte) 0x70, (byte) 0xB0,
            (byte) 0x50, (byte) 0x90, (byte) 0x91, (byte) 0x51, (byte) 0x93, (byte) 0x53, (byte) 0x52, (byte) 0x92, (byte) 0x96, (byte) 0x56, (byte) 0x57, (byte) 0x97, (byte) 0x55, (byte) 0x95, (byte) 0x94, (byte) 0x54,
            (byte) 0x9C, (byte) 0x5C, (byte) 0x5D, (byte) 0x9D, (byte) 0x5F, (byte) 0x9F, (byte) 0x9E, (byte) 0x5E, (byte) 0x5A, (byte) 0x9A, (byte) 0x9B, (byte) 0x5B, (byte) 0x99, (byte) 0x59, (byte) 0x58, (byte) 0x98,
            (byte) 0x88, (byte) 0x48, (byte) 0x49, (byte) 0x89, (byte) 0x4B, (byte) 0x8B, (byte) 0x8A, (byte) 0x4A, (byte) 0x4E, (byte) 0x8E, (byte) 0x8F, (byte) 0x4F, (byte) 0x8D, (byte) 0x4D, (byte) 0x4C, (byte) 0x8C,
            (byte) 0x44, (byte) 0x84, (byte) 0x85, (byte) 0x45, (byte) 0x87, (byte) 0x47, (byte) 0x46, (byte) 0x86, (byte) 0x82, (byte) 0x42, (byte) 0x43, (byte) 0x83, (byte) 0x41, (byte) 0x81, (byte) 0x80, (byte) 0x40
    };

    /**
     * 查表法计算CRC16校验
     * 注：此算法来自网友共享
     * @param data 需要计算的字节数组
     */
    public static String getCRC16(byte[] data) {
        int crc = 0x0000ffff;
        int ucCRCHi = 0x00ff;
        int ucCRCLo = 0x00ff;
        int iIndex;
        for (int i = 0; i < data.length; ++i) {
            iIndex = (ucCRCLo ^ data[i]) & 0x00ff;
            ucCRCLo = ucCRCHi ^ crc16_h[iIndex];
            ucCRCHi = crc16_l[iIndex];
        }

        crc = ((ucCRCHi & 0x00ff) << 8) | (ucCRCLo & 0x00ff) & 0xffff;
//        //高低位互换，输出符合相关工具对Modbus CRC16的运算
//        crc = ( (crc & 0xFF00) >> 8) | ( (crc & 0x00FF ) << 8);
        return String.format("%04X", crc);
    }
    
    public final static String hex2ip(String ipHex) {
    	return MixUtil.hex2short("00" + ipHex.substring(0,2)) + "." + MixUtil.hex2short("00" + ipHex.substring(2,4)) + "." + MixUtil.hex2short("00" + ipHex.substring(4,6)) + "." + MixUtil.hex2short("00" + ipHex.substring(6,8));
    }
    
    public final static String hex2mac(String macHex) {
    	return macHex.substring(0,2) + "-" + macHex.substring(2,4) + "-" + macHex.substring(4,6) + "-" + macHex.substring(6,8) + "-" + macHex.substring(8,10);
    }

    /**
     * 内网IP
     * @return
     * @throws SocketException
     */
    public static String localIP() throws SocketException{
        Enumeration<?> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
        InetAddress ip = null;
        String localHostIP = null;
        List<InetAddress> cache = new ArrayList<>();
        while (allNetInterfaces.hasMoreElements()){
            NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
            Enumeration<?> addresses = netInterface.getInetAddresses();
            while (addresses.hasMoreElements()){
                ip = (InetAddress) addresses.nextElement();
                System.out.println("：：：：：：：：：：："+ip.getHostAddress());
                if (ip != null && ip instanceof Inet4Address){
                    if(!ip.isLoopbackAddress() && ip.isSiteLocalAddress()){
                        localHostIP = ip.getHostAddress();
                        System.out.println("本机的IPV4 = " + ip.getHostAddress());
                    }else{
                        cache.add(ip);
                    }
                    
                } else if(ip instanceof Inet6Address){
                    if(!ip.isLoopbackAddress() && ip.isSiteLocalAddress()){
                        localHostIP = ip.getHostAddress();
                        System.out.println("本机的IPV6 = " + ip.getHostAddress());
                    }else{
                        cache.add(ip);
                    }
                }
            }
        }
        
        if(localHostIP != null){
            return localHostIP;
        }else{
            for (InetAddress inetAddress : cache) {
                if(inetAddress.isSiteLocalAddress()){
                    System.out.println("取本地地址ip="+inetAddress.getHostAddress());
                    return inetAddress.getHostAddress();
                }
            }
        }
        return null;
    }

	@SuppressWarnings("resource")
	public static int localAvailablePort() throws IOException {
		ServerSocket serverSocket = new ServerSocket(0);
        int port = serverSocket.getLocalPort();
        return port;
    }

	public static String getCurrTime() {
		Date now = new Date();
		SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");
		String s = outFormat.format(now);
		return s;
	}

	public static String getCurrLogTime() {
		Date now = new Date();
		SimpleDateFormat outFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
		String s = outFormat.format(now);
		return s;
	}

	/**
	 * 时间转16进制字符串
	 */
	public static String date2HStr(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		StringBuilder builder = new StringBuilder();
		String milliSecond = String.format("%04X", (calendar.get(Calendar.SECOND) * 1000) + calendar.get(Calendar.MILLISECOND));
		builder.append(milliSecond.substring(2, 4));
		builder.append(milliSecond.substring(0, 2));
		builder.append(String.format("%02X", calendar.get(Calendar.MINUTE) & 0x3F));
		builder.append(String.format("%02X", calendar.get(Calendar.HOUR_OF_DAY) & 0x1F));
		int week = calendar.get(Calendar.DAY_OF_WEEK);
		if (week == Calendar.SUNDAY) {
			week = 7;
		}
		else {
			week--;
		}
		builder.append(String.format("%02X", (week << 5) + (calendar.get(Calendar.DAY_OF_MONTH) & 0x1F)));
		builder.append(String.format("%02X", calendar.get(Calendar.MONTH) + 1));
		builder.append(String.format("%02X", calendar.get(Calendar.YEAR) - 2000));
		return builder.toString();
	}

    /**
     * 补位操作.
     *
     * @param data
     * @param length
     * @param span
     * @param fillDirect
     * @return String
     */
    public final static String fillData(String data, int length, char span, Direction fillDirect) {
        if (data.length() == length - 1) {
            return fillData(data, span, fillDirect);
        }

        if (fillDirect != Direction.LEFT && fillDirect != Direction.RIGHT) {
            return data;
        }
        StringBuilder strTmp = new StringBuilder(data);
        final boolean isLeft = (fillDirect == Direction.LEFT);
        if (isLeft) {
            if (strTmp.length() < length) {
                for (int i = length - strTmp.length(); i > 0; i--) {
                    strTmp.insert(0, span);
                }
            }
        }
        else {
            if (strTmp.length() < length) {
                for (int i = length - strTmp.length(); i > 0; i--) {
                    strTmp.append(span);
                }
            }
        }
        return strTmp.toString();
    }

    /**
     * 仅仅补一位的补位操作.
     *
     * @param data
     * @param span
     * @param fillDirect
     * @return String
     */
    public final static String fillData(String data, char span, Direction fillDirect) {
        if (fillDirect != Direction.LEFT && fillDirect != Direction.RIGHT) {
            return data;
        }
        if (fillDirect == Direction.LEFT) {
            return span + data;
        }
        else {
            return data + span;
        }
    }

    /**
     * 补位操作.<br/>
     * 直接对字节数组进行补位得到新的字节数组
     *
     * @param buf
     * @param length
     * @param span
     * @param fillDirect
     * @return byte[]
     */
    public final static byte[] fillData(byte[] buf, int length, char span, Direction fillDirect) {
        if (fillDirect != Direction.LEFT && fillDirect != Direction.RIGHT) {
            return buf;
        }
        byte[] newBuffer;
        final boolean isLeft = (fillDirect == Direction.LEFT);
        if (isLeft) {
            if (buf.length < length) {
                newBuffer = new byte[length];
                System.arraycopy(buf, 0, newBuffer, length - buf.length, buf.length);
                for (int i = length - buf.length - 1; i >= 0; i--) {
                    newBuffer[i] = (byte) span;
                }
                return newBuffer;
            }
        }
        else {
            if (buf.length < length) {
                newBuffer = new byte[length];
                System.arraycopy(buf, 0, newBuffer, 0, buf.length);
                for (int i = buf.length; i < length; i++) {
                    newBuffer[i] = (byte) span;
                }
                return newBuffer;
            }
        }

        return buf;
    }

    /**
     * 去补位操作. 和补位操作刚好相反
     *
     * @param data
     * @param length
     * @param fillDirect
     * @return String
     */
    public final static String unfillData(String data, int length, Direction fillDirect) {
        if (fillDirect != Direction.LEFT && fillDirect != Direction.RIGHT) {
            return data;
        }

        if (data.length() == (length - 1)) {
            return unfillData(data, fillDirect);
        }

        StringBuilder strTmp = new StringBuilder(data);
        final boolean isLeft = (fillDirect == Direction.LEFT);
        if (isLeft) {
            if (strTmp.length() > length) {
                for (int i = strTmp.length() - length; i > 0; i--) {
                    strTmp.deleteCharAt(0);
                }
            }
        }
        else {
            if (strTmp.length() > length) {
                for (int i = strTmp.length() - length; i > 0; i--) {
                    strTmp.deleteCharAt(strTmp.length() - 1);
                }
            }
        }
        return strTmp.toString();
    }

    /**
     * 仅仅去补一位的去补位操作.
     *
     * @param data
     * @param fillDirect
     * @return String
     */
    public final static String unfillData(String data, Direction fillDirect) {
        if (fillDirect != Direction.LEFT && fillDirect != Direction.RIGHT) {
            return data;
        }

        if (data.isEmpty()) {
            return data;
        }

        if (fillDirect == Direction.LEFT) {
            return data.substring(1);
        }
        else {
            return data.substring(0, data.length() - 1);
        }
    }

    /**
     * 去补位操作. 和补位操作刚好相反<br/>
     * 直接对字节数组进行反补位得到新的字节数组
     *
     * @param buf
     * @param length
     * @param span
     * @param fillDirect
     * @return byte[]
     */
    public final static byte[] unfillData(byte[] buf, int length, char span, Direction fillDirect) {
        if (fillDirect != Direction.LEFT && fillDirect != Direction.RIGHT) {
            return buf;
        }

        byte[] newBuffer;
        final boolean isLeft = (fillDirect == Direction.LEFT);
        if (isLeft) {
            if (buf.length > length) {
                newBuffer = new byte[length];
                // 左反补位，需要跳过buf.length - length的长度
                System.arraycopy(buf, buf.length - length, newBuffer, 0, length);
                return newBuffer;
            }
        }
        else {
            if (buf.length > length) {
                newBuffer = new byte[length];
                // 右反补位，直接丢弃右边的多于信息
                System.arraycopy(buf, 0, newBuffer, 0, length);
                return newBuffer;
            }
        }

        return buf;
    }

    /**
     * 补位和截取函数.<br/>
     *
     * @param data
     * @param length
     * @param span
     * @param fillDirect
     * @return String
     */
    public static String pack(String data, int length, char span, Direction fillDirect) {
        if (fillDirect != Direction.LEFT && fillDirect != Direction.RIGHT) {
            return data;
        }

        if (data == null) {
            data = "";
        }
        // 长度超长则截取
        if (data.length() > length) {
            if (fillDirect == Direction.LEFT) {
                // 左截取
                return data.substring(data.length() - length);
            }
            else {
                // 右截取
                return data.substring(0, length);
            }
        }
        else {
            return fillData(data, length, span, fillDirect);
        }
    }

    public static byte[] trimeLeft(byte[] tmpBuf) {
        byte blank = (byte) 32;
        int i = 0;
        for (; i < tmpBuf.length; i++) {
            if (tmpBuf[i] != blank) {
                break;
            }
        }
        byte[] buf = new byte[tmpBuf.length - i];
        System.arraycopy(tmpBuf, i, buf, 0, buf.length);
        return buf;

    }

    /**
     * 消除字节数组里面的右边所有空格.<br/>
     * 此方法已经经过测试
     *
     * @param tmpBuf
     * @return byte[]
     */
    public static byte[] trimeRight(byte[] tmpBuf) {
        byte blank = (byte) 32;
        int index = tmpBuf.length - 1;
        for (; index >= 0; index--) {
            if (tmpBuf[index] != blank) {
                // 将尾部指向第一个空字符
                index++;
                break;
            }
        }
        byte[] buf = new byte[index];
        System.arraycopy(tmpBuf, 0, buf, 0, index);
        return buf;
    }

    public static byte[] trimeAll(byte[] tmpBuf) {
        byte blank = (byte) 32;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        int i = 0;
        for (; i < tmpBuf.length; i++) {
            if (tmpBuf[i] != blank) {
                bos.write(tmpBuf[i]);
            }
        }
        return bos.toByteArray();
    }

    public static byte[] trim(byte[] tmpBuf) {
        byte blank = (byte) 32;
        int left = 0;
        for (; left < tmpBuf.length; left++) {
            if (tmpBuf[left] != blank)
            {
                break;
            }
        }
        int right = tmpBuf.length - 1;
        for (; right >= 0; right--) {
            if (tmpBuf[right] != blank) {
                // 将尾部指向第一个空字符
                right++;
                break;
            }
        }
        byte[] buf = new byte[right - left];
        System.arraycopy(tmpBuf, left, buf, 0, buf.length);
        return null;
    }

    /**
     * 比较字节数组.<br/>
     * @param bytes1
     * @param bytes2
     * @return boolean
     */
    public static boolean compareBytes(byte[] bytes1, byte[] bytes2) {
        if ((bytes1 == null) || (bytes2 == null)) {
            return false;
        }

        if ((bytes1.length != bytes2.length)) {
            return false;
        }

        for (int i = 0; i < bytes1.length; i++) {
            if (bytes1[i] != bytes2[i]) {
                return false;
            }
        }

        return true;
    }

	public static byte[] subbytes(byte[] compressedData, int start, int end) {
		byte[] buf = new byte[end - start];
		System.arraycopy(compressedData, start, buf, 0, buf.length);
		
		return buf;
	}

	public static byte[] concatbytes(byte[] buf1, byte[] buf2) {
		byte[] buf = new byte[buf1.length + buf2.length];
		System.arraycopy(buf1, 0, buf, 0,           buf1.length);
		System.arraycopy(buf2, 0, buf, buf1.length, buf2.length);
		
		return buf;
	}

	public static String formatIpAddress(String ip, String port){
		return String.format("%s%s%s",ip.trim(), ConstantValue.CONNECTOR_CHAR, port.trim());
	}
	
    public final static void main(String[] args) {
//        String replaceHex = MixUtil.replaceHex(MixUtil.replaceHex("01022202032304", "22","2201"),"23", "2202");
//        System.out.println(replaceHex);
//        replaceHex = MixUtil.replaceHex(MixUtil.replaceHex(replaceHex, "2202","23"),"2201", "22");
//        System.out.println(replaceHex);
//        System.out.println(MixUtil.Sbyte2short(MixUtil.hex2bytes("6A00")));
//        System.out.println(MixUtil.Sbyte2short(MixUtil.hex2bytes("6900")));
//
//        System.out.println(MixUtil.bytes2hex(MixUtil.Sshort2byte((short)106)));
//        System.out.println(MixUtil.bytes2hex(MixUtil.Sshort2byte((short)105)));
        
//        String pileNo = "20210000000000129";
//        String hex = MixUtil.pack(pileNo, 32, '0', Direction.RIGHT);
//        System.out.println(hex);
//        System.out.println(MixUtil.bytes2hex(MixUtil.hex2bytes(hex)));
//        System.out.println(MixUtil.Sbyte2short(MixUtil.hex2bytes("7301")));
//        System.out.println(MixUtil.Sbyte2short(MixUtil.hex2bytes("2009")));
//        System.out.println(MixUtil.Sbyte2short(MixUtil.hex2bytes("0100")));
//        int len = 0xFF;
//        System.out.println();
//        System.out.println(MixUtil.hex2byte("FF"));
        //        682C000000013002021000000300020A56312E332E360000010000000000000000000004C0A801A60080E10001A640EA
//        String str = "000000023002021000000300";
//        String crc = getCRC16(MixUtil.hex2bytes(str));
//        voltOutValue=E515
//        ampOutValue=C400
        int voltage = MixUtil.Sbyte2short(MixUtil.hex2bytes("800C"));
        //充电桩电流输出值
        int electricity = MixUtil.Sbyte2short(MixUtil.hex2bytes("3100"));
        System.out.println(voltage);
        System.out.println(electricity);
        String pileNo="30020190000020";
        String gunNo="02";
        String transNo = pileNo + gunNo + MixUtil.bcd2str(MixUtil.str2bcd(MixUtil.getCurrTime())) + "00";
        System.out.println(transNo);
        transNo = MixUtil.pack(pileNo+gunNo+MixUtil.bcd2str(MixUtil.str2bcd(MixUtil.getCurrTime())), 32, '0', Direction.RIGHT);
        System.out.println(transNo);
//        System.out.println(MixUtil.Sbyte2int(MixUtil.hex2bytes("E3010000")));
//        System.out.println(MixUtil.bytes2hex(MixUtil.Sint2byte(3759)));
//        System.out.println(MixUtil.hex2str("4C43304346344344354B31303231343031", 0, 34));
//        System.out.println(MixUtil.str2hex("LJ1EFKRN0G4204276"));
//        System.out.println(MixUtil.int2hex(50));
//        System.out.println(MixUtil.byte2int(MixUtil.hex2bytes("0000001B")));
//        System.out.println(MixUtil.byte2short(MixUtil.hex2bytes("0508")));
//        System.out.println(MixUtil.hex2ip("C0A80168"));
//        System.out.println(MixUtil.bcdHex2DigitStr("1605010A"));
//        
//        System.out.println(MixUtil.date2HStr(new Date()));
        System.out.println(Float.intBitsToFloat(Integer.parseInt("43667A08", 16)));
    }
}
